package com.secxiot.common.utils;

import com.gexin.fastjson.JSONObject;
import com.gexin.rp.sdk.base.IBatch;
import com.gexin.rp.sdk.base.IPushResult;
import com.gexin.rp.sdk.base.impl.SingleMessage;
import com.gexin.rp.sdk.base.impl.Target;
import com.gexin.rp.sdk.base.payload.APNPayload;
import com.gexin.rp.sdk.base.payload.VoIPPayload;
import com.gexin.rp.sdk.exceptions.RequestException;
import com.gexin.rp.sdk.http.IGtPush;
import com.gexin.rp.sdk.template.*;
import com.gexin.rp.sdk.template.style.AbstractNotifyStyle;
import com.gexin.rp.sdk.template.style.Style0;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.Map;

/**
 * The type G push util.
 */
public class GPushUtil {

    private static Logger log = LoggerFactory.getLogger(GPushUtil.class);

    private static void pushToSingle(PushParam pushParam) {
//        AbstractTemplate template = PushTemplate.getNotificationTemplate(); //通知模板(点击后续行为: 支持打开应用、发送透传内容、打开应用同时接收到透传 这三种行为)
//        AbstractTemplate template = PushTemplate.getLinkTemplate(); //点击通知打开(第三方)网页模板
//        AbstractTemplate template = PushTemplate.getTransmissionTemplate(); //透传消息模版
//        AbstractTemplate template = PushTemplate.getRevokeTemplate(); //消息撤回模版
        AbstractTemplate template = PushTemplate.getStartActivityTemplate(pushParam); //点击通知, 打开（自身）应用内任意页面

        // 单推消息类型
        SingleMessage message = getSingleMessage(template);
        Target target = new Target();
        target.setAppId(pushParam.appEmum.appId);
        target.setClientId(pushParam.cid);
        target.setAlias(pushParam.alias); //别名需要提前绑定

        IPushResult ret = null;
        try {
            ret =  pushParam.appEmum.push.pushMessageToSingle(message, target);
        } catch (RequestException e) {
            log.info("GPUSH首次推送异常，二次尝试", e);
            ret =  pushParam.appEmum.push.pushMessageToSingle(message, target, e.getRequestId());
        }
        if (ret != null) {
            log.info(ret.getResponse().toString());
        } else {
            log.error("GPUSH服务器响应异常");
        }
    }

    /**
     * 批量单推
     *
     * 当单推任务较多时，推荐使用该接口，可以减少与服务端的交互次数。
     */
    private static void pushToSingleBatch(PushParam pushParam) {
        IBatch batch = pushParam.appEmum.push.getBatch();

        IPushResult ret = null;
        try {
            //构建客户a的透传消息a
            constructClientTransMsg(pushParam);
            //构建客户B的点击通知打开网页消息b
            constructClientLinkMsg(pushParam);
            ret = batch.submit();
        } catch (Exception e) {
            log.info("GPUSH首次推送异常，二次尝试", e);
            try {
                ret = batch.retry();
            } catch (IOException ex) {
                log.info("GPUSH二次推送异常:", ex);
            }
        }
        if (ret != null) {
            log.info(ret.getResponse().toString());
        } else {
            log.error("GPUSH服务器响应异常");
        }
    }

    private static void constructClientTransMsg(PushParam pushParam) throws Exception {
        AbstractTemplate template = PushTemplate.getTransmissionTemplate(pushParam);
        SingleMessage message = getSingleMessage(template);

        // 设置推送目标，填入appid和clientId
        Target target = new Target();
        target.setAppId(pushParam.appEmum.appId);
        target.setClientId(pushParam.cid);
        pushParam.batch.add(message, target);
    }

    private static void constructClientLinkMsg(PushParam pushParam) throws Exception {
        AbstractTemplate template = PushTemplate.getLinkTemplate(pushParam);
        SingleMessage message = getSingleMessage(template);

        // 设置推送目标，填入appid和clientId
        Target target = new Target();
        target.setAppId(pushParam.appEmum.appId);
        target.setClientId(pushParam.cid);
        pushParam.batch.add(message, target);
    }

    private static SingleMessage getSingleMessage(AbstractTemplate template) {
        SingleMessage message = new SingleMessage();
        message.setData(template);
        // 设置消息离线，并设置离线时间
        message.setOffline(true);
        // 离线有效时间，单位为毫秒，可选
        message.setOfflineExpireTime(72 * 3600 * 1000);
        message.setPriority(1);
        message.setPushNetWorkType(0); // 判断客户端是否wifi环境下推送。1为仅在wifi环境下推送，0为不限制网络环境，默认不限
        return message;
    }

    public static class PushTemplate {

        /**
         * 点击通知打开应用模板, 在通知栏显示一条含图标、标题等的通知，用户点击后激活您的应用。
         * 通知模板(点击后续行为: 支持打开应用、发送透传内容、打开应用同时接收到透传 这三种行为)
         * @return
         */
        public static NotificationTemplate getNotificationTemplate(PushParam pushParam) {
            NotificationTemplate template = new NotificationTemplate();
            // 设置APPID与APPKEY
            template.setAppId(pushParam.appEmum.appId);
            template.setAppkey(pushParam.appEmum.appkey);
            //设置展示样式
            template.setStyle(PushStyle.getStyle0(pushParam.title, pushParam.content, pushParam.logo, pushParam.channelLevel));
            template.setTransmissionType(1);  // 透传消息设置，收到消息是否立即启动应用： 1为立即启动，2则广播等待客户端自启动
            template.setTransmissionContent(pushParam.transmissionContent);
//        template.setSmsInfo(PushSmsInfo.getSmsInfo()); //短信补量推送

//        template.setDuration("2019-07-09 11:40:00", "2019-07-09 12:24:00");  // 设置定时展示时间，安卓机型可用
            // 在消息推送的时候设置notifyid。如果需要覆盖此条消息，则下次使用相同的notifyid发一条新的消息。客户端sdk会根据notifyid进行覆盖。
            template.setNotifyid(pushParam.notifyid);

            return template;
        }

        /**
         * 点击通知打开(第三方)网页模板, 在通知栏显示一条含图标、标题等的通知，用户点击可打开您指定的网页。
         * @return
         */
        public static LinkTemplate getLinkTemplate(PushParam pushParam) {
            LinkTemplate template = new LinkTemplate();
            // 设置APPID与APPKEY
            template.setAppId(pushParam.appEmum.appId);
            template.setAppkey(pushParam.appEmum.appkey);

            //设置展示样式
            template.setStyle(PushStyle.getStyle0(pushParam.title, pushParam.content, pushParam.logo, pushParam.channelLevel));
            template.setUrl(pushParam.linkUrl);  // 设置打开的网址地址
            template.setNotifyid(pushParam.notifyid); // 在消息推送的时候设置notifyid。如果需要覆盖此条消息，则下次使用相同的notifyid发一条新的消息。客户端sdk会根据notifyid进行覆盖。
//         template.setSmsInfo(PushSmsInfo.getSmsInfo()); //短信补量推送
//        template.setDuration("2019-07-09 11:40:00", "2019-07-09 12:24:00");  // 设置定时展示时间，安卓机型可用
            return template;
        }

        /**
         * 透传消息模版,透传消息是指消息传递到客户端只有消息内容，展现形式由客户端自行定义。客户端可自定义通知的展现形式，也可自定义通知到达之后的动作，或者不做任何展现。
         * @return
         */
        public static TransmissionTemplate getTransmissionTemplate(PushParam pushParam) {
            TransmissionTemplate template = new TransmissionTemplate();
            // 设置APPID与APPKEY
            template.setAppId(pushParam.appEmum.appId);
            template.setAppkey(pushParam.appEmum.appkey);

            //透传消息设置，1为强制启动应用，客户端接收到消息后就会立即启动应用；2为等待应用启动
            template.setTransmissionType(1);
            template.setTransmissionContent("透传内容"); //透传内容
            //ios消息推送
            if (AppEmum.IOS.equals(pushParam.appEmum)) {
                template.setAPNInfo(getAPNPayload(pushParam.category, pushParam.customMsg, pushParam.alertMsg, pushParam.voicePlayMessage));
            }
//        template.setAPNInfo(getVoIPPayload());
//        template.setSmsInfo(PushSmsInfo.getSmsInfo()); //短信补量推送
            return template;
        }

        //点击通知, 打开（自身）应用内任意页面
        public static StartActivityTemplate getStartActivityTemplate(PushParam pushParam) {
            StartActivityTemplate template = new StartActivityTemplate();
            // 设置APPID与APPKEY
            template.setAppId(pushParam.appEmum.appId);
            template.setAppkey(pushParam.appEmum.appkey);
            //设置展示样式
            template.setStyle(PushStyle.getStyle0(pushParam.title, pushParam.content, pushParam.logo, pushParam.channelLevel));
            //ios消息推送
            if (AppEmum.IOS.equals(pushParam.appEmum)) {
                template.setAPNInfo(getAPNPayload(pushParam.category, pushParam.customMsg, pushParam.alertMsg, pushParam.voicePlayMessage));
            }
            String intent = "intent:#Intent;component=com.yourpackage/.NewsActivity;end";

            template.setIntent(pushParam.intent); //最大长度限制为1000
            template.setNotifyid(pushParam.notifyid); // 在消息推送的时候设置notifyid。如果需要覆盖此条消息，则下次使用相同的notifyid发一条新的消息。客户端sdk会根据notifyid进行覆盖。
//        template.setSmsInfo(PushSmsInfo.getSmsInfo()); //短信补量推送
//        template.setDuration("2019-07-09 11:40:00", "2019-07-09 12:24:00");  // 设置定时展示时间，安卓机型可用
            return template;
        }

        /**
         * IOS消息载体
         *
         * @param category 在客户端通知栏触发特定的action和button显示
         * @param customMsg 客户自定义增加自定义的数据,Key-Value形式
         * @param alertMsg 通知消息体
         * @param voicePlayMessage 用户自定义播放内容
         * @return
         */
        private static APNPayload getAPNPayload(String category, Map<String,String> customMsg, String alertMsg, String voicePlayMessage) {
            APNPayload payload = new APNPayload();
            //在已有数字基础上加1显示，设置为-1时，在已有数字上减1显示，设置为数字时，显示指定数字
            payload.setAutoBadge("+1");
            payload.setContentAvailable(1);
            //ios 12.0 以上可以使用 Dictionary 类型的 sound
            payload.setSound("default");
            if (StringUtils.isNotBlank(category)) {
                payload.setCategory(category);
            }
            if (!CollectionUtils.isEmpty(customMsg)) {
                for (String key:customMsg.keySet()) {
                    payload.addCustomMsg(key, customMsg.get(key));
                }
            }

            //简单模式APNPayload.SimpleMsg
            if (StringUtils.isNotBlank(alertMsg)) {
                payload.setAlertMsg(new APNPayload.SimpleAlertMsg(alertMsg));
            }
//        payload.setAlertMsg(getDictionaryAlertMsg());  //字典模式使用APNPayload.DictionaryAlertMsg

            //设置语音播报类型，int类型，0.不可用 1.播放body 2.播放自定义文本
            if (StringUtils.isNotBlank(voicePlayMessage)) {
                payload.setVoicePlayType(2);
                //设置语音播报内容，String类型，非必须参数，用户自定义播放内容，仅在voicePlayMessage=2时生效
                //注：当"定义类型"=2, "定义内容"为空时则忽略不播放
                payload.setVoicePlayMessage(voicePlayMessage);
            }


            // 添加多媒体资源
/*
            payload.addMultiMedia(new MultiMedia().setResType(MultiMedia.MediaType.pic)
                    .setResUrl("资源文件地址")
                    .setOnlyWifi(true));
*/
            return payload;
        }

        private static APNPayload.DictionaryAlertMsg getDictionaryAlertMsg() {
            APNPayload.DictionaryAlertMsg alertMsg = new APNPayload.DictionaryAlertMsg();
            alertMsg.setBody("body1");
            alertMsg.setActionLocKey("显示关闭和查看两个按钮的消息");
            alertMsg.setLocKey("loc-key");
            alertMsg.addLocArg("loc-ary1");
            alertMsg.addLocArg("loc-ary2");
            alertMsg.setLaunchImage("调用已经在应用程序中绑定的图形文件名");
            // iOS8.2以上版本支持
            alertMsg.setTitle("通知标题");
            alertMsg.setTitleLocKey("自定义通知标题");
            alertMsg.addTitleLocArg("自定义通知标题组1");
            alertMsg.addTitleLocArg("自定义通知标题组2");

            alertMsg.setSubtitle("sub-title");
            alertMsg.setSubtitleLocKey("sub-loc-key1");
            alertMsg.addSubtitleLocArgs("sub-loc-arg1");
            alertMsg.addSubtitleLocArgs("sub-loc-arg2");
            return alertMsg;
        }

        /**
         * 需要使用iOS语音传输，请使用VoIPPayload代替APNPayload
         * @return
         */
        private static VoIPPayload getVoIPPayload() {
            VoIPPayload payload = new VoIPPayload();
            JSONObject jo = new JSONObject();
            jo.put("key1", "value1");
            payload.setVoIPPayload(jo.toString());
            return payload;
        }
    }

    public static class PushStyle {
        
        /**
         * Style0 系统样式
         * @link http://docs.getui.com/getui/server/java/template/ 查看效果
         * @return
         */
        public static AbstractNotifyStyle getStyle0(String title, String content, String logo, Integer channelLevel) {
            Style0 style = new Style0();
            // 设置通知栏标题与内容
            style.setTitle(title);
            style.setText(content);
            // 配置通知栏图标
            style.setLogo("icon.png"); //配置通知栏图标，需要在客户端开发时嵌入，默认为AppInfo.push.png
            if (StringUtils.isNotBlank(logo)) {
                style.setLogo(logo);
            }

            // 设置通知是否响铃，震动，或者可清除
            style.setRing(true);
            style.setVibrate(true);
            style.setClearable(true);
            style.setChannel("通知渠道id");
            style.setChannelName("通知渠道名称");
            style.setChannelLevel(3); //设置通知渠道重要性
            if (channelLevel != null) {
                style.setChannelLevel(channelLevel);
            }
            return style;
        }

    }

    public static enum AppEmum {
        IOS("appId","appkey","masterSecret");

        private String appId;
        private String appkey;
        private String masterSecret;
        private IGtPush push;

        AppEmum(String appId, String appkey, String masterSecret) {
            this.appId = appId;
            this.appkey = appkey;
            this.masterSecret = masterSecret;
            this.push = new IGtPush(appkey, masterSecret);;
        }



    }

    public class PushParam {

        public AppEmum appEmum;

        public String title = "您有一条新通知";
        public String content = "";
        public String logo = "icon.png";
        public Integer channelLevel = 3;
        public Integer notifyid;
        public String intent = "intent:#Intent;component=com.yourpackage/.NewsActivity;end";
        public String linkUrl;
        public String transmissionContent;

        //IOS
        public String category;
        public Map<String,String> customMsg;
        public String alertMsg;
        public String voicePlayMessage;

        public String cid;
        public String alias;
        public IBatch batch;

        public PushParam() {}

        public PushParam(AppEmum appEmum, String title, String content, String cid, String alias) {
            this.appEmum = appEmum;
            this.title = title;
            this.content = content;
            this.cid = cid;
            this.alias = alias;
        }
    }

/*    public static class AppInfo {
        public static final String APPID = "";
        public static final String APPKEY = "";
        public static final String MASTERSECRET = "";



        public static final String DEVICETOKEN = "";

        public static final String CID = "";
        public static final String CID_2 = "";

        public static final String ALIAS = "alias1";
        public static final String ALIAS_2 = "alias2";

        public static final String TAG = "tag1";
        public static final String TAG_2 = "tag2";

        public static final String PNMD5 = "xxxx";

        public static IGtPush push = new IGtPush(APPKEY, MASTERSECRET);
    }*/

}
